{"cells":[{"cell_type":"markdown","metadata":{},"source":["Renommez ce Notebook (ne me demandez pas comment faire, mais cherchez par vous même).
\n","**Dès que vous avez terminé, téléchargez votre notebook et envoyez le sur école directe.**"]},{"cell_type":"markdown","metadata":{},"source":["Téléchargez le fichier zip contenant les images : **cliquez ici** \n","\n","Uploadez ensuite ce fichier pour qu'il soit utilisable sur votre notebook."]},{"cell_type":"markdown","metadata":{},"source":["Ces données correspondent à une version très réduite du dataset MNIST, une base de données de chiffres écrits à la main.\n","Les images en noir et blanc sont plus petites (10x10) que les images originales.\n","\n","Le but de ce TP sera d'utiliser l'algorithme des k plus proches voisins à l'aide de la librairie scikit-learn : \n","\n","afin de reconnaître **automatiquement** le chiffre correspondant à l'image."]},{"cell_type":"markdown","metadata":{},"source":["# Mission 1 : récupérer les labels et afficher une image"]},{"cell_type":"markdown","metadata":{},"source":["Exécutez la cellule ci-dessous.
\n","Astuce : vous pouvez cliquer sur **Ctrl + Entrée** pour exécuter la cellule actuelle."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["import zipfile\n","import glob\n","from sklearn.neighbors import KNeighborsClassifier\n","from sklearn.model_selection import train_test_split\n","import numpy as np\n","from pathlib import Path\n","from IPython.display import display\n","from PIL import Image\n","\n","DOSSIER = \"./*/*/*.jpg\"\n","\n","with zipfile.ZipFile('./mnist_small.zip', 'r') as z:\n"," z.extractall('./')"]},{"cell_type":"markdown","metadata":{},"source":["## 1.1 Récupérer les labels"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["glob.glob(\"./*/*/*.jpg\")"]},{"cell_type":"markdown","metadata":{},"source":["Nous venons de lister le chemin de chacune des images. **Vous remarquerez que le nom du dossier parent correspond au chiffre associé à l'image**, c'est ce que nous appellerons \"labels\"."]},{"cell_type":"markdown","metadata":{},"source":["La méthode **split** permet de découper une chaîne de caractère en utilisant un séparateur.\n","Par exemple : "]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["'hasta_la_vista_nsi'.split('_')"]},{"cell_type":"markdown","metadata":{},"source":["Dans le cas d'un apprentissage supervisé, l'algorithme va avoir besoin des labels associés à chaque image. Dans notre cas, pour une image correspondant à un 1, nous devons associer à cette image le label ```1```.\n","\n","Copiez et complétez le code ci-dessous pour récupérer dans la liste ```labels``` l'ensemble des chiffres qui correspondent à chaque image :"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["def lire_images():\n"," \"\"\" Lire les images contenues dans le dossier et les chiffres associés (labels)\n"," \"\"\" \n"," lst_images_numpy = []\n"," labels = []\n"," liste_nom_images = glob.glob(f'{DOSSIER}')\n","\n"," for chemin_image in liste_nom_images:\n"," img = Image.open(chemin_image)\n"," lst_images_numpy.append(np.array(img, dtype='int16'))\n"," # Pour l'apprentissage supervisé, le dossier parent correspond à la classe de l'image (le chiffre)\n"," labels.append(chemin_image.split('/')[COMPLETER ICI])\n"," return lst_images_numpy, labels"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["lst_images_numpy, labels = lire_images()"]},{"cell_type":"markdown","metadata":{},"source":["Vérifier le résultat (vous devriez obtenir une série de chiffres allant de zéro à neuf)."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["labels"]},{"cell_type":"markdown","metadata":{},"source":["## 1.2 Afficher le premier tableau et la première image"]},{"cell_type":"markdown","metadata":{},"source":["Vous devez afficher la première image. Pour cela vous devrez utiliser la liste ```lst_images_numpy```"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["from matplotlib import pyplot as plt\n","\n","def afficher_image(image):\n"," \"\"\" Afficher le premier tableau et la première image\n"," \"\"\"\n"," display(image)\n"," plt.imshow(image)\n"," plt.show()\n","\n","afficher_image(# TODO: passer le premier tableau numpy en argument)"]},{"cell_type":"raw","metadata":{},"source":["⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⡾⣻⣿⣿⣿⣿⣯⣍⠛⠻⢷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⠟⢁⣾⠟⠋⣁⣀⣤⡉⠻⣷⡀⠀⠙⢿⣷⣄⠀⠀⠀⠀⠀⠀\n","⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⣰⣿⠏⠀⠀⢸⣿⠀⠼⢋⣉⣈⡳⢀⣿⠃⠀⠀⠀⠙⣿⣦⡀⠀⠀⠀⠀\n","⠀⠀⠀⠀⠀⠀⢰⡿⠿⣷⡀⠀⠀⠀⣼⣿⠃⠀⠀⣀⣤⡿⠟⠛⠋⠉⠉⠙⢛⣻⠶⣦⣄⡀⠀⠘⣿⣷⡀⠀⠀⠀\n","⢠⣾⠟⠳⣦⣄⢸⡇⠀⠈⣷⡀⠀⣼⣿⡏⢀⣤⡾⢋⣵⠿⠻⢿⠋⠉⠉⢻⠟⠛⠻⣦⣝⠻⣷⣄⠸⣿⣿⠀⠀⠀\n","⠘⣧⠀⠀⠀⠙⢿⣿⠀⠀⢸⣷⠀⣿⣿⣧⣾⣏⡴⠛⢡⠖⢛⣲⣅⠀⠀⣴⣋⡉⠳⡄⠈⠳⢬⣿⣿⣿⡿⠀⠀⠀\n","⠀⠘⠷⣤⣀⣀⣀⣽⡶⠛⠛⠛⢷⣿⣿⣿⣿⣏⠀⠀⡏⢰⡿⢿⣿⠀⠀⣿⠻⣿⠀⡷⠀⣠⣾⣿⡿⠛⠷⣦⠀⠀\n","⠀⠀⢀⣾⠟⠉⠙⣿⣤⣄⠀⢀⣾⠉⠀⢹⣿⣿⣷⠀⠹⡘⣷⠾⠛⠋⠉⠛⠻⢿⡴⢃⣄⣻⣿⣿⣷⠀⠀⢹⡇⠀\n","⠀⠀⢸⡇⠈⠉⠛⢦⣿⡏⠀⢸⣧⠀⠈⠻⣿⡿⢣⣾⣦⣽⠃⠀⠀⠀⠀⠀⠀⠀⣷⣾⣿⡇⠉⢿⡇⠀⢀⣼⠇⠀\n","⠀⠀⠘⣷⡠⣄⣀⣼⠇⠀⠀⠀⠻⣷⣤⣀⣸⡇⠀⠹⣿⣿⣦⣀⠀⠀⠀⠀⢀⣴⣿⣿⡟⠀⠀⢸⣷⣾⡿⠃⠀⠀\n","⠀⠀⠀⠈⠻⢦⣍⣀⣀⣀⡄⠀⣰⣿⡿⠿⢿⣇⠀⠀⠉⠛⠻⣿⣿⡷⠾⣿⣿⡿⠉⠁⠀⠀⢀⣾⠋⠁⠀⠀⠀⠀\n","⠀⠀⠀⠀⠀⠀⠈⠉⠉⠙⠿⢿⣿⣇⠀⠀⠈⢿⣧⣄⠀⠀⠀⢹⣷⣶⣶⣾⣿⡇⠀⠀⣀⣴⡿⣧⣄⡀⠀⠀⠀⠀\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣷⡀⠀⠀⠙⢿⣿⣶⣤⡀⠻⢤⣀⡤⠞⢀⣴⣿⣿⠟⢷⡀⠙⠻⣦⣄⠀⠀\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣦⠀⢠⡟⠁⠙⢻⣿⠷⠶⣶⠶⠾⠛⠙⣿⠇⠀⠀⢻⡄⠀⠀⠙⢷⡀\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⡀⣿⠁⣤⣤⡄⢻⡶⠶⠛⠛⠛⠛⠛⣿⢠⣾⣷⣆⢻⡀⠀⠀⠈⣷\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⢸⣿⣿⣿⡈⢿⡀⠀⠀⠀⠀⠀⡿⢸⣿⣿⣿⢸⡇⠀⠀⠀⡟\n","⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠈⠉⠉⠉⠁⠈⠁⠀⠀⠀⠀⠈⠁⠈⠉⠉⠉⠀⠁⠀⠀⠈⠁\n"]},{"cell_type":"markdown","metadata":{},"source":["# Mission 2 : Utiliser l'algorithme des k plus proches voisins\n"]},{"cell_type":"markdown","metadata":{},"source":["La bibliothèque Python scikit-learn propose un grand nombre d’algorithmes lié à l’apprentissage automatique. Parmi\n","tous ces algorithmes, scikit-learn propose l’algorithme des 𝑘 plus proches voisins. Nous ne rentrerons pas dans les détails mais sachez qu'il existe différentes manières d'implémenter cet algorithme, notamment pour améliorer la complexité de l'algorithme que nous avons vu en cours.\n","\n","Après avoir étudié la documentation : \n","\n","Listez les types d'algorithmes utilisables pour les k plus proches voisins."]},{"cell_type":"markdown","metadata":{},"source":["**Ajoutez votre réponse ici**"]},{"cell_type":"markdown","metadata":{},"source":["Pour mesurer la distance entre les différentes observations (des images dans notre cas), une métrique est utilisée. Après avoir fait des - recherches sur internet et en étudiant la documentation (voir lien ci-dessus), expliquez à quoi correspond la métrique par défaut utilisée\n"]},{"cell_type":"markdown","metadata":{},"source":["**Ajoutez votre réponse ici**"]},{"cell_type":"markdown","metadata":{},"source":["Le classifieur (c'est du franglais) attend en paramètre des tableaux numpy en une dimension. Or pour le moment nos tableaux sont des tableaux de tableaux qui sont contenus dans une liste. Il nous faut obtenir une liste qui contient des tableaux. Pour cela nous devons \"aplatir\" le tableau de deux dimensions "]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["lst_images_numpy[0]"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["lst_images_numpy[0].ndim"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["def aplatir_images(lst_images_numpy):\n"," \"\"\" Crée une nouvelle liste contenant les tableaux numpy aplatie\n"," \"\"\"\n"," # TODO : créer une liste vide \n"," \n"," # TODO : boucle sur toutes les images (tableaux numpy)\n"," lst_images_numpy_aplati.append(image.flatten())\n"," return lst_images_numpy_aplati\n"," \n","lst_images_numpy = aplatir_images(lst_images_numpy)\n","lst_images_numpy[0]"]},{"cell_type":"markdown","metadata":{},"source":["On doit obtenir un tableau de une dimension."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["assert lst_images_numpy[0].ndim == 1"]},{"cell_type":"markdown","metadata":{},"source":["On va créer un échantillon pour l'apprentissage et un échantillon pour tester notre modèle."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["(trainRI, testRI, trainRL, testRL) = train_test_split(\n","\tlst_images_numpy, labels, test_size=0.25, random_state=42)"]},{"cell_type":"markdown","metadata":{},"source":["On peut lancer l'apprentissage avec un type d'algorithme similaire à celui qu'on a vu en cours (non optimisé au point de vue de la complexité algorithmique)."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["model = KNeighborsClassifier(algorithm= \"brute\", n_neighbors=5)\n","model.fit(trainRI, trainRL)"]},{"cell_type":"markdown","metadata":{},"source":["On évalue notre modèle."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["acc = model.score(testRI, testRL)\n","\"précision : {:.2f}%\".format(acc * 100)"]},{"cell_type":"markdown","metadata":{},"source":["Essayez avec plusieurs valeurs pour le nombre de voisins."]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["# Essai 1"]},{"cell_type":"code","execution_count":null,"metadata":{"trusted":false},"outputs":[],"source":["# Essai 2"]},{"cell_type":"markdown","metadata":{},"source":["Trouver la valeur optimale pour le pramètre **k** n'est pas évident. Il existe des suggestions théoriques, et ce qu'on appelle la validation croisée qui permet de vérifier expérimentalement si le paramètre k est optimal. Mais tout cela dépasse largement le cadre de ce cours."]},{"cell_type":"markdown","metadata":{},"source":["Vous pouvez regarder ici pour en savoir plus sur la validation croisée et la recherche du paramètre optimal : \n"," \n","- https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html\n"]},{"cell_type":"raw","metadata":{},"source":["\n"," $$$$$$\\ \n","$$ __$$\\ \n","$$ / \\__|$$\\ $$\\ $$$$$$\\ $$$$$$\\ $$$$$$\\ \n","\\$$$$$$\\ $$ | $$ |$$ __$$\\ $$ __$$\\ $$ __$$\\ \n"," \\____$$\\ $$ | $$ |$$ / $$ |$$$$$$$$ |$$ | \\__|\n","$$\\ $$ |$$ | $$ |$$ | $$ |$$ ____|$$ | \n","\\$$$$$$ |\\$$$$$$ |$$$$$$$ |\\$$$$$$$\\ $$ | \n"," \\______/ \\______/ $$ ____/ \\_______|\\__| \n"," $$ | \n"," $$ | \n"," \\__| \n","⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬛⬛⬛⬛⬛⬛⬜⬜⬜⬜⬜⬜⬜⬜\n","⬜⬜⬜⬜⬜⬜⬜⬜⬛⬛⬜⬜🟥🟥⬜⬜⬛⬛⬜⬜⬜⬜⬜⬜\n","⬜⬜⬜⬜⬜⬜⬜⬛🟥🟥⬜🟥⬜⬜🟥⬜🟥🟥⬛⬜⬜⬜⬜⬜\n","⬜⬜⬜⬜⬜⬛⬛🟥🟥🟥⬜🟥🟥🟥🟥⬜🟥🟥🟥⬛⬜⬜⬜⬜\n","⬜⬛⬛⬜⬛⬜⬜⬛🟥🟥⬛⬛⬛⬛⬛⬛🟥🟥🟥⬛⬜⬜⬜⬜\n","⬛⬜⬜⬛⬛⬜⬜⬛⬛⬛🟥🟥🟥🟥🟥🟥⬛⬛🟥🟥⬛⬜⬜⬜\n","⬛⬜⬜⬜⬛⬜⬜⬛🟥🟥⬛⬛⬛⬛⬛⬛🟥🟥⬛🟥⬛⬜⬜⬜\n","⬜⬛⬜⬜⬛⬛⬛⬛⬛⬛⬜⬜🏻🏻⬜⬜⬛⬛🟫⬛⬛⬜⬜⬜\n","⬛⬜⬜⬜⬛⬜⬜⬜⬛⬜⬜⬛🏻🏻⬛⬜⬜🏻🟫🏻🏻⬛⬜⬜\n","⬛⬜⬜⬜⬛⬜⬜⬜⬛⬜⬜⬛🏻🏻⬛⬜⬜🏻⬛🏻🏻⬛⬜⬜\n","⬛⬜⬜⬜🟦⬛⬛⬜⬛🏻🏻🏻🏻🏻🏻🏻🏻🏻🏻⬛🏻⬛⬜⬜\n","⬜⬛⬛🟦🟦🟦🟦⬛🏻🏻⬛🏻🏻🏻🏻⬛🏻🏻🏻⬛🏻⬛⬜⬜\n","⬜⬜⬜⬛⬛⬛⬛🟥⬛⬛⬛⬛🏻🏻⬛⬛⬛⬛🏻⬛⬛⬜⬜⬜\n","⬜⬜⬜⬜⬛🟥🟥🟥⬛⬛⬛⬛⬛⬛⬛⬛⬛🏻⬛⬜⬜⬜⬜⬜\n","⬜⬜⬜⬜⬛🟥🟥🟥🟥⬛🏻⬛⬛⬛⬛🏻🏻⬛⬛⬜⬜⬜⬜⬜\n","⬜⬜⬜⬜⬜⬛🟥🟥🟥⬛⬛🏻🏻🏻🏻⬛⬛🟥🟥⬛⬛⬜⬜⬜\n","⬜⬜⬜⬜⬜⬛🟥🟥🟥🟦🟦⬛⬛⬛⬛🟥🟦⬛🟥🟥🟥⬛⬜⬜\n","⬜⬜⬜⬜⬜⬜⬛🟥🟦🟦🟦🟦🟥🟥🟥🟥🟦⬛🟥🟥🟥🟥⬛⬜\n","⬜⬜⬜⬜⬜⬜⬜⬛🟦🟦🟨🟨🟦🟥🟥🟦🟨🟨⬛🟥🟥🟥⬛⬜\n","⬜⬜⬜⬜⬜⬜⬜⬛🟦🟦🟨🟨🟦🟦🟦🟦🟨🟨⬛🟥🟥🟥⬛⬜\n","⬜⬜⬜⬜⬜⬜⬜⬛🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛🟥🟥⬛⬜⬜\n","⬜⬜⬜⬜⬜⬜⬜⬛🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛⬛⬜⬜⬜\n","⬜⬜⬜⬜⬜⬜⬛🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛⬜⬜⬜⬜\n","⬜⬜⬜⬜⬜⬜⬛🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛⬜⬜⬜⬜\n","⬜⬜⬜⬜⬜⬛🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛⬜⬜⬜\n","⬜⬜⬜⬜⬜⬛🟦🟦🟦🟦🟦⬛⬛⬛⬛🟦🟦🟦🟦🟦⬛⬜⬜⬜\n","⬜⬜⬜⬛⬛⬛🟦🟦🟦🟦⬛⬛⬛⬛⬛⬛🟦🟦🟦🟦⬛⬛⬛⬜\n","⬜⬜⬛⬛🏻🏻🟫🟫🟧🟧🟫⬛⬜⬜⬛🟫🟧🟧🟫🟫🏻🏻⬛⬛\n","⬜⬜⬜⬛🟧🟧🟧🟧🟧🟧🟧⬛⬜⬜⬛🟧🟧🟧🟧🟧🟧🟧⬛⬜\n","⬜⬜⬜⬜⬛⬛⬛⬛⬛⬛⬛⬜⬜⬜⬜⬛⬛⬛⬛⬛⬛⬛⬜⬜\n"," \n"," "]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":2}